package com.alibaba.cirtus.ots.application.adapter.ability.facade.service.sap;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;

import javax.annotation.Resource;

import com.alibaba.cirtus.ots.application.adapter.ability.utils.InfoUtil;
import com.alibaba.citrus.ots.common.annotation.ProcessInvoker;
import com.alibaba.citrus.ots.common.exception.FacadeException;
import com.alibaba.citrus.ots.common.lock.RedisLock;
import com.alibaba.citrus.ots.common.util.IntegrateUtils;
import com.alibaba.citrus.ots.common.util.SapAndCrmFieldDealUtils;
import com.alibaba.cz.base.tool.log.Log;

import com.alibaba.fastjson.JSON;
import com.alibaba.lattice2.epoch.sdk.model.Result;
import com.epoch.app.bcots.contants.BcOtsConstants;
import com.epoch.app.otsapplicationadaptersdk.model.dto.SapRetrySaveRequest;
import com.epoch.app.otsapplicationadaptersdk.model.enums.RetryStatus;
import com.epoch.app.otsapplicationadaptersdk.model.enums.SapApiCode;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapCommResponse;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapCommSDO;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapIf008Request;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapIf008SDO;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapIf018Request;
import com.epoch.app.otsapplicationadaptersdk.sap.MnSapIf018SDO;
import com.epoch.app.otsapplicationadaptersdk.sap.mnsapif018.service.MnSapIf018Service;
import com.epoch.app.otsapplicationadaptersdk.sapretrywrite.service.SapRetryWriteService;
import com.epoch.app.otsb2btradecenter.domain.order.dto.LoadOrderListRequest;
import com.epoch.app.otsb2btradecenter.domain.order.model.Order;
import com.epoch.app.otsb2btradecenter.domain.order.service.OrderService;
import com.epoch.app.otsb2btradecenter.domain.orderline.dto.OrderLineLoadListRequest;
import com.epoch.app.otsb2btradecenter.domain.orderline.model.OrderLine;
import com.epoch.app.otsb2btradecenter.domain.orderline.service.OrderLineService;
import com.epoch.app.otsunifiedinventory.api.allocateorderwrite.service.AllocateOrderWriteService;
import com.epoch.app.otsunifiedinventory.api.consignmentorderwrite.service.ConsignmentOrderWriteService;
import com.epoch.app.otsunifiedinventory.consignmentorder.model.ConsignmentOrder;
import com.epoch.app.otsunifiedinventory.consignmentorder.service.ConsignmentOrderService;
import com.epoch.app.otsunifiedinventory.consignmentorderline.model.ConsignmentOrderLine;
import com.epoch.app.otsunifiedinventory.consignmentorderline.service.ConsignmentOrderLineService;
import com.epoch.app.otsunifiedinventory.model.dto.AllocateOrderCancelDeliveredRequest;
import com.epoch.app.otsunifiedinventory.model.dto.AllocateOrderDeliveryRequest;
import com.epoch.app.otsunifiedinventory.model.dto.ConsignmentOrderLineLoadListRequest;
import com.epoch.app.otsunifiedinventory.model.dto.ConsignmentOrderLoadListRequest;
import com.epoch.app.otsunifiedinventory.model.dto.ConsignmentOrderWriteUpdateRequest;
import com.epoch.app.otsunifiedinventory.model.dto.InvOperateLine;
import com.epoch.app.otsunifiedinventory.model.dto.OccupyReleaseRequest;
import com.epoch.app.otsunifiedinventory.model.dto.OccupyReleaseResponse;
import com.epoch.app.otsunifiedinventory.model.dto.OccupyRequest;
import com.epoch.app.otsunifiedinventory.model.dto.WmsSDO;
import com.epoch.app.otsunifiedinventory.service.OtsUnifiedInventoryService;
import com.google.common.collect.Lists;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;

@Service
public class MnSapIf018ServiceImpl implements MnSapIf018Service {
    private static final Log LOG = Log.getLogger(MnSapIf018ServiceImpl.class);

    @Resource
    private ConsignmentOrderWriteService consignmentOrderWriteService;
    @Resource
    private AllocateOrderWriteService allocateOrderWriteService;
    @Resource
    private ConsignmentOrderService consignmentOrderService;
    @Resource
    private SapRetryWriteService sapRetryWriteService;
    @Resource
    private OrderService orderService;
    @Resource
    private OrderLineService orderLineService;
    @Resource
    private ConsignmentOrderLineService consignmentOrderLineService;
    @Resource
    private OtsUnifiedInventoryService otsUnifiedInventoryService;

    private static final String DELIVERY_ORDER_LOCK = "DELIVERY_ORDER_LOCK_";

    @Override
    @ProcessInvoker(remark = "MnSapIf018Service", errorCode = "", printLog = true)
    public MnSapCommResponse externalSyncDeliveryOrder(MnSapIf018Request mnSapIf018Request) {
        MnSapCommResponse response = new MnSapCommResponse();
        //能否释放预占
        boolean canOccupyRelease = false;
        // Try to get from mogodb if null
        if (mnSapIf018Request == null) {
            mnSapIf018Request = IntegrateUtils.safeGetMessageObject(MnSapIf018Request.class);
        }

        response.setMessageId(mnSapIf018Request.getMessageHeader().getMessageId());
        response.setInterfacePath(mnSapIf018Request.getMessageHeader().getInterfacePath());

        AllocateOrderDeliveryRequest allocateOrderDeliveryRequest = new AllocateOrderDeliveryRequest();
        for (MnSapIf018SDO data : mnSapIf018Request.getData()) {
            //2022.05.18 如果交货单删除时还找不到 那就要重试
            ConsignmentOrderLoadListRequest consignmentOrderLoadListRequest = new ConsignmentOrderLoadListRequest();
            consignmentOrderLoadListRequest.setOuterDeliveryOrderId(SapAndCrmFieldDealUtils.generateIdField(data.getDeliveryOrderId()));
//            consignmentOrderLoadListRequest.setStatus(1);
            Result<List<ConsignmentOrder>> loadConsignmentOrderList = consignmentOrderService.loadConsignmentOrderList(consignmentOrderLoadListRequest);
            if (Objects.isNull(loadConsignmentOrderList) || CollectionUtils.isEmpty(loadConsignmentOrderList.getResult())){
                LOG.error("sapDelConsignmentOrderError:{}", JSON.toJSONString(mnSapIf018Request));
                List<MnSapCommSDO> mnSapCommSDOS = new ArrayList<>();
                MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();
                mnSapCommSDO.setMessage("交货单不存在");
                mnSapCommSDO.setStatus("E");
                mnSapCommSDOS.add(mnSapCommSDO);
                response.setData(mnSapCommSDOS);
                //写入重试表
                saveSapRetry(mnSapIf018Request,"交货单不存在");
                return response;
            }
            Integer status = loadConsignmentOrderList.getResult().get(0).getStatus();
            if (Objects.equals(status,0)){

            }
            ConsignmentOrderWriteUpdateRequest request = new ConsignmentOrderWriteUpdateRequest();
            request.setOuterDeliveryOrderId(SapAndCrmFieldDealUtils.generateIdField(data.getDeliveryOrderId()));
            consignmentOrderWriteService.deleteBySapDeliveryOrder(request);
            try {
                //更改调拨单的交货数量
                AllocateOrderCancelDeliveredRequest cancelDeliveredRequest = new AllocateOrderCancelDeliveredRequest();
                cancelDeliveredRequest.setDeliveryOrderId(data.getDeliveryOrderId());
                allocateOrderWriteService.cancelDelivered(cancelDeliveredRequest);
            } catch (Exception e) {
                LOG.error("MnSapIf018Service.externalSyncDeliveryOrder error", e);
            }
            //加锁 锁住交货单号
            try(RedisLock lock = new RedisLock(BcOtsConstants.REDIS_CACHE_CODE(),DELIVERY_ORDER_LOCK + SapAndCrmFieldDealUtils.generateIdField(data.getDeliveryOrderId()),
                    5 * 60 * 1000,10 * 60 * 1000)){
                if (!lock.lock()){
                    List<MnSapCommSDO> mnSapCommSDOS = new ArrayList<>();
                    MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();
                    mnSapCommSDO.setMessage("获取分布式锁错误");
                    mnSapCommSDO.setStatus("E");
                    mnSapCommSDOS.add(mnSapCommSDO);
                    response.setData(mnSapCommSDOS);
                    //写入重试表
                    saveSapRetry(mnSapIf018Request,"获取分布式锁错误");
                    return response;
                }
                occupyRelease(SapAndCrmFieldDealUtils.generateIdField(data.getDeliveryOrderId()));

            }catch (Throwable e){
                LOG.error("DelDeliveryOrderLockError:{},exception:{}", JSON.toJSONString(mnSapIf018Request),e);
                List<MnSapCommSDO> mnSapCommSDOS = new ArrayList<>();
                MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();
                mnSapCommSDO.setMessage(e.getMessage());
                mnSapCommSDO.setStatus("E");
                mnSapCommSDOS.add(mnSapCommSDO);
                response.setData(mnSapCommSDOS);
                //写入重试表
                saveSapRetry(mnSapIf018Request,e.getMessage());
                return response;
            }
        }

        List<MnSapCommSDO> mnSapCommSDOS = new ArrayList<>();
        MnSapCommSDO mnSapCommSDO = new MnSapCommSDO();
        mnSapCommSDO.setMessage("成功");
        mnSapCommSDO.setStatus("S");
        mnSapCommSDOS.add(mnSapCommSDO);
        response.setData(mnSapCommSDOS);
        return response;
    }

    public void saveSapRetry(MnSapIf018Request request,String code) {
        try {
            if (request == null || StringUtils.isBlank(code)) {
                return;
            }
            MnSapIf018SDO sdo = request.getData().get(0);
            SapRetrySaveRequest sapRetrySaveRequest = new SapRetrySaveRequest();
            String requestJson = JSON.toJSONString(request);
            sapRetrySaveRequest.setParam(requestJson);
            sapRetrySaveRequest.setMsg(code);
            sapRetrySaveRequest.setMessageId(request.getMessageHeader().getMessageId());
            //请求时间戳
//            sapRetrySaveRequest.setRequestTime(sdo.getExt());
            sapRetrySaveRequest.setApiCode(SapApiCode.SAP018.getValue());
            sapRetrySaveRequest.setOutKey(sdo.getDeliveryOrderId());
            sapRetrySaveRequest.setStatus(RetryStatus.FAIL.getValue());
            sapRetryWriteService.save(sapRetrySaveRequest);
        } catch (Throwable e) {
            LOG.error("sapRetrySaveError", e);
        }
    }

    //首先要判断是不是销售单
    private boolean occupyRelease(String outDeliveryOrderNo){
        OccupyReleaseRequest occupyReleaseRequest = new OccupyReleaseRequest();
        //判断此次018是否是销售单的
        ConsignmentOrderLoadListRequest consignmentOrderLoadListRequest = new ConsignmentOrderLoadListRequest();
        consignmentOrderLoadListRequest.setOuterDeliveryOrderId(outDeliveryOrderNo);
        Result<List<ConsignmentOrder>> loadConsignmentOrderList = consignmentOrderService.loadConsignmentOrderList(consignmentOrderLoadListRequest);
        //交货单需要存在
        if (loadConsignmentOrderList == null || CollectionUtils.isEmpty(loadConsignmentOrderList.getResult())){

            throw new FacadeException("OTS-03-005-00-15-160");
        }
        ConsignmentOrder consignmentOrder = loadConsignmentOrderList.getResult().get(0);
        //交货单需要处于删除状态
        if (!Objects.equals(0,consignmentOrder.getStatus())){
            LOG.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrder:{}",JSON.toJSONString(outDeliveryOrderNo),JSON.toJSONString(consignmentOrder));
            throw new FacadeException("OTS-03-005-00-15-161");
        }
        //判断一下
        String outerSalesOrderId = StringUtils.isNotBlank(consignmentOrder.getOuterSalesOrderId())?
                consignmentOrder.getOuterSalesOrderId() : consignmentOrder.getOuterStoOrderId();
        //如果销售单存在查销售单
        if (StringUtils.isBlank(outerSalesOrderId)){
            throw new FacadeException("OTS-03-005-00-15-162");
        }
        LoadOrderListRequest loadOrderListRequest = new LoadOrderListRequest();
        loadOrderListRequest.setOuterOrderId(outerSalesOrderId);
        Result<List<Order>> orderListResult = orderService.loadOrderList(loadOrderListRequest);
        //如果是销售单
        if (orderListResult != null && CollectionUtils.isNotEmpty(orderListResult.getResult())){
            List<Order> orderList = orderListResult.getResult();
            Order order = orderList.get(0);
            //逻辑仓库id
            String wareHouseCode = order.getWareHouseCode();
            //获取仓库档案id
            //获取交货单明细
            ConsignmentOrderLineLoadListRequest consignmentOrderLineLoadListRequest = new ConsignmentOrderLineLoadListRequest();
            consignmentOrderLineLoadListRequest.setConsignmentOrderId(consignmentOrder.getId().toString());
            Result<List<ConsignmentOrderLine>> listResult = consignmentOrderLineService.loadConsignmentOrderLineList(consignmentOrderLineLoadListRequest);
            if (listResult != null && CollectionUtils.isNotEmpty(listResult.getResult())){
                //获取 outSOLineId - quantity 理论上行不会重复
                Map<String, List<ConsignmentOrderLine>> lineMap = listResult.getResult().stream().collect(Collectors.groupingBy(ConsignmentOrderLine::getOuterSoLineId));
                List<InvOperateLine> invOperateLineList = Lists.newArrayList();
                lineMap.forEach((k,v)->{
                    InvOperateLine invOperateLine = new InvOperateLine();
                    if (CollectionUtils.isEmpty(v)){
                        //error
                        LOG.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}",JSON.toJSONString(outDeliveryOrderNo),JSON.toJSONString(lineMap));
                       throw new FacadeException("OTS-03-005-00-15-163");
                    }
                    String scItemId = v.get(0).getScItemId();
                    if (StringUtils.isBlank(scItemId)){
                        //error
                        LOG.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}",JSON.toJSONString(outDeliveryOrderNo),JSON.toJSONString(lineMap));
                        throw new FacadeException("OTS-03-005-00-15-164");
                    }
                    invOperateLine.setGoodsId(scItemId);
                    invOperateLine.setDeleted(true);
                    invOperateLine.setType("2");
                    invOperateLine.setOutOrderId(outDeliveryOrderNo);
                    //发现没有时间戳 用交货单号代替了.
                    invOperateLine.setOutSubOrderId(outDeliveryOrderNo);
                    invOperateLine.setWarehouseAreaId(wareHouseCode);
                    //
                    WmsSDO wmsSDO = InfoUtil.getWmsSDO(wareHouseCode);
                    if (StringUtils.isBlank(wmsSDO.getWarehouseId())){
                        //error
                        LOG.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}",JSON.toJSONString(outDeliveryOrderNo),JSON.toJSONString(lineMap));
                        throw new FacadeException("OTS-03-005-00-15-165");
                    }
                    invOperateLine.setWarehouseId(wmsSDO.getWarehouseId());
                    invOperateLine.setReferenceOrderId(order.getId().toString());
                    OrderLineLoadListRequest orderLineLoadListRequest = new OrderLineLoadListRequest();
                    orderLineLoadListRequest.setMainOrderId(order.getId().toString());
                    orderLineLoadListRequest.setOuterOrderLineId(k);
                    LOG.info("MnSapIf018ServiceImpl_occupyRelease_loadOrderLine_request:{}",JSON.toJSONString(orderLineLoadListRequest));
                    Result<List<OrderLine>> lineResult = orderLineService.loadOrderLineList(orderLineLoadListRequest);
                    if (lineResult == null || CollectionUtils.isEmpty(lineResult.getResult())){
                        //error
                        LOG.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}",JSON.toJSONString(outDeliveryOrderNo),JSON.toJSONString(lineMap));
                        throw new FacadeException("OTS-03-005-00-15-166");
                    }
                    OrderLine orderLine = lineResult.getResult().get(0);
                    invOperateLine.setReferenceSubOrderId(orderLine.getId().toString());
                    Long quantity = v.stream().mapToLong(x -> {
                        if (StringUtils.isBlank(x.getQty())) {
                            return 0L;
                        }
                        BigDecimal bigDecimal = new BigDecimal(x.getQty().trim());
                        return bigDecimal.movePointRight(3).longValue();
                    }).sum();
                    if (quantity <= 0 ){
                        //error
                        LOG.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}",JSON.toJSONString(outDeliveryOrderNo),JSON.toJSONString(lineMap));
                        throw new FacadeException("OTS-03-005-00-15-167");
                    }
                    invOperateLine.setQuantity(quantity.toString());
                    invOperateLineList.add(invOperateLine);
                });
                if (CollectionUtils.isEmpty(invOperateLineList)){
                    //error
                    LOG.error("MnSapIf018ServiceImpl_occupyRelease_Error,request:{},consignmentOrderLine:{}",JSON.toJSONString(outDeliveryOrderNo),JSON.toJSONString(lineMap));
                    throw new FacadeException("OTS-03-005-00-15-168");
                }
                occupyReleaseRequest.setInvOperateLineList(invOperateLineList);
                LOG.info("MnSapIf018ServiceImpl_occupyRelease,request:{},occupyReleaseRequest:{}",JSON.toJSONString(outDeliveryOrderNo),JSON.toJSONString(occupyReleaseRequest));
                Result<OccupyReleaseResponse> occupyReleaseResponseResult = otsUnifiedInventoryService.occupyRelease(occupyReleaseRequest);
                LOG.info("MnSapIf018ServiceImpl_occupyRelease,request:{},occupyReleaseRequest:{},occupyReleaseResult:{}",JSON.toJSONString(outDeliveryOrderNo),JSON.toJSONString(occupyReleaseRequest),JSON.toJSONString(occupyReleaseResponseResult));
                if (occupyReleaseResponseResult == null || !occupyReleaseResponseResult.isSuccess()){
                    //error
                    throw new FacadeException("OTS-03-005-00-15-169");
                }
            }
        }
        return true;
    }
}
